-- ======================================================================
-- Hell Logic Sniffer Addon 
-- 
-- Copyright 2013 Hell-Prototypes
--
-- http://www.hellprototypes.com/
-- ======================================================================

ModuleClass = "LS_PLUGIN"
ModuleName  = "SPI Analyse"
ModuleTip   = "Analyse SPI bus decoded data"

VAR_KEY_SS   = "SPI_Analyse_SS"
VAR_KEY_MOSI = "SPI_Analyse_MOSI"
VAR_KEY_MISO = "SPI_Analyse_MISO"

g_sampling_period = 20

function time_consuming(start_, end_)
	local ns = (end_ - start_) * g_sampling_period
	local us = ns/1000
	local ms = us/1000
	
	return ns, us, ms
end

function get_ss_mosi_miso_channel_number()
	local ss = LS_API.ReadVariable(VAR_KEY_SS)
	if not ss then ss = 0 end

	local mosi = LS_API.ReadVariable(VAR_KEY_MOSI)
	if not mosi then mosi = 1 end

	local miso = LS_API.ReadVariable(VAR_KEY_MISO)
	if not miso then miso = 2 end

	local channels = LS_API.MultiInputBox({"SS Channel", ss, "MOSI Channel", mosi, "MISO Channel", miso })
    if channels then
		if #channels ~= 3 then
			return nil;
		end
	else
		return nil
    end
	
	if ss ~= channels[1] then
		LS_API.SaveVariable(VAR_KEY_SS, channels[1])
	end
	if mosi ~= channels[2] then
		LS_API.SaveVariable(VAR_KEY_MOSI, channels[2])
	end
	if miso ~= channels[3] then
		LS_API.SaveVariable(VAR_KEY_MISO, channels[3])
	end

	return channels[1], channels[2], channels[3]
end

function get_bit_level(ch_num, bit_index )
    local level = LS_API.GetChannelLevelByIndex(ch_num, bit_index);
	if level == 0 then
		return false
	else
		return true
    end
end

function get_decode_data_by_ss(ss_start, ss_end, Decoded_Data, index_base)
	local index = index_base;
	local element = ""
	while index < #Decoded_Data do
        local bit_index = Decoded_Data[index]
        if bit_index > ss_start then
            if bit_index > ss_end then
                break
            end
            element = element .. Decoded_Data[index+1] .. " "
        end
        index = index + 2
	end
	return element, index
end

function main ()
	local ns, us, ms = 0
	local param = LS_API.GetCommonParameter()
	if #param < 4 then
		LS_API.MessageBox("Error param : table size : " .. #param)
		return
	end
	g_sampling_period = param[1]

    local SS, MOSI, MISO = get_ss_mosi_miso_channel_number()
	if not (SS and MOSI and MISO) then
		--LS_API.MessageBox("Invalid input")
		return
    end

    local MOSI_Decoded_Data = LS_API.GetChannelDecodedData(MOSI)
    
    if type(MOSI_Decoded_Data) ~= "table" then
		LS_API.MessageBox("No decoded data found in channel : " .. MOSI)
		return
	end
	local MISO_Decoded_Data = LS_API.GetChannelDecodedData(MISO)
    
    if type(MISO_Decoded_Data) ~= "table" then
		LS_API.MessageBox("No decoded data found in channel : " .. MISO)
		return
	end

    local l_ss_falling_edge_table = LS_API.GetChannelNegedgeTable(SS)
    if type(l_ss_falling_edge_table) ~= "table" then
    	LS_API.MessageBox("Get SS falling edge data fail...")
		return
    end
    local l_ss_rising_edge_table  = LS_API.GetChannelPosedgeTable(SS)
    if type(l_ss_rising_edge_table) ~= "table" then
    	LS_API.MessageBox("Get SS rising edge data fail...")
		return
    end
    LS_API.DebugMsg("falling  " .. #l_ss_falling_edge_table)
    LS_API.DebugMsg("rising  " .. #l_ss_rising_edge_table)

    LS_API.ReportPushBack("========================================================")
    LS_API.ReportPushBack("SPI bus data analyse, Decode data length : " .. #MOSI_Decoded_Data/2)
	LS_API.ReportPushBack("========================================================\r\n")

    local index = 1
	local element = ""
    local ss_falling_index = 1
    local ss_rising_index = 1
    while l_ss_falling_edge_table[ss_falling_index] > l_ss_rising_edge_table[ss_rising_index] do
        ss_rising_index = ss_rising_index + 1
    end
    local ss_start = l_ss_falling_edge_table[ss_falling_index]
    local ss_end = l_ss_rising_edge_table[ss_rising_index]

    while true do
		local mosi_data, index_mosi = get_decode_data_by_ss(ss_start, ss_end, MOSI_Decoded_Data, index)
		local miso_data, index_miso = get_decode_data_by_ss(ss_start, ss_end, MISO_Decoded_Data, index)
		if index_mosi ~= index_miso then
			LS_API.DebugMsg("index_mosi ~= index_mosi")
			break;
		end
		
		ns, us, ms = time_consuming(ss_start, ss_end)
		LS_API.ReportPushBack(string.format("Time Cost : %.2fms", ms))
		if #mosi_data > 0 then
			LS_API.ReportPushBack(string.format("MOSI: %d Bytes Sended, %.2fns/Byte", (index_mosi-index)/2, 2*ns/(index_mosi-index)))
			LS_API.ReportPushBack(mosi_data)
		end
		
		if #miso_data > 0 then
			LS_API.ReportPushBack(string.format("MISO: %d Bytes Sended, %.2fns/Byte", (index_miso-index)/2, 2*ns/(index_miso-index)))
			LS_API.ReportPushBack(miso_data)
		end

		index = index_mosi

		ss_falling_index = ss_falling_index + 1
		if ss_falling_index <= #l_ss_falling_edge_table then
			ss_start = l_ss_falling_edge_table[ss_falling_index]
		else
			break;
		end 
		local last_ss_end = ss_end
		ss_rising_index = ss_rising_index + 1
		if ss_rising_index <= #l_ss_rising_edge_table then
			ss_end = l_ss_rising_edge_table[ss_rising_index]
		else
			break;
		end

		ns, us, ms = time_consuming(last_ss_end, ss_start)
		local time = string.format("\r\n===Time Gap : %.1fns = %.2fus = %.3fms\r\n", ns, us, ms)
		LS_API.ReportPushBack(time)
	end
end
